package zhongbo.javaweb.instagram.schedule;

import com.alibaba.fastjson.TypeReference;
import com.mongodb.MongoException;
import com.mongodb.client.result.UpdateResult;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import zhongbo.javaweb.instagram.dto.JsonRespDto;
import zhongbo.javaweb.instagram.enums.InsUrl;
import zhongbo.javaweb.instagram.enums.ServiceType;
import zhongbo.javaweb.instagram.service.ProcessService;
import zhongbo.javaweb.instagram.util.DateFormatUtil;
import zhongbo.javaweb.instagram.util.JsonRespUtil;
import zhongbo.javaweb.instagram.util.SysUtil;
import zhongbo.javaweb.instagram.web.controller.InsPostController;
import zhongbo.javaweb.instagram.web.util.RestTemplateUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 说明：
 *
 * @author zhongboWork
 * @version 1.0
 * @since 2022-01-19 14:25
 */
@Component
@Slf4j
@Data
public class PostDataSchedule {

    @Autowired
    private RestTemplateUtils restTemplateUtils;
    @Autowired
    private ProcessService processService;

    @Autowired
    private InsPostController insPostController;

    @Value("${service.type}")
    private ServiceType serviceType;
    @Value("${service.middle.url}")
    private String middleUrl;

    @Value("${post.pageNumber}")
    private int pageNumber = 1;
    @Value("${post.pageSize}")
    private int pageSize = 100;

    @Value("${post.check.intervalMs}")
    private long fileCheckIntervalMs = 60000;


    private long lastCheckTime;

    private AtomicLong atomicLong = new AtomicLong(0);

    private boolean isUpdateImagePath = false;


    //@Scheduled(fixedDelay = 1000)
    public void checkHeartbeat() {
        if (System.currentTimeMillis() - lastCheckTime > fileCheckIntervalMs) {
            lastCheckTime = System.currentTimeMillis();
            if (serviceType == ServiceType.client) {
                log.info("======== 客户端 [数据] 同步, 间隔配置 {}", DateFormatUtil.formatMs(fileCheckIntervalMs));
                if (!SysUtil.isWindows()) {
                    log.error("客户端 [数据] 同步失败! 未在windows系统下运行");
                    return;
                }
                syncLastPost(middleUrl);
            }
        }
    }

    private void syncLastPost(String middleUrl) {
        // http://e.7mo.org:8068/Ins/post?pageSize=100&pageNumber=1
        String postUrl = String.format(InsUrl.POST_LIST_FORMAT, pageSize, pageNumber);
        JsonRespDto<List<String>> respDto = restTemplateUtils.get(middleUrl + postUrl, new TypeReference<JsonRespDto<List<String>>>() {
        });
        long past = System.currentTimeMillis() - lastCheckTime;
        if (JsonRespUtil.isSuccess(respDto)) {
            List<String> data = respDto.getData();
            log.warn("获取数据时间! past {}", DateFormatUtil.formatMs(past));
            List<Document> fileList = extractPostList(data);
            if (fileList == null) {
                log.warn("解析数据失败! data {}", data);
                return;
            }
            if (fileList.isEmpty()) {
                log.warn("同步数据完成! 没有新的数据 {} 已同步 {}", fileList, atomicLong.get());
                return;
            }
            synchronizePosts(fileList);
        } else {
            log.warn("获取数据失败! past {}", DateFormatUtil.formatMs(past));
        }
    }

    private void synchronizePosts(List<Document> fileList) {
        for (Document document : fileList) {
            long start = System.currentTimeMillis();
            String id = null;
            try {
                id = document.getString("id");
                // 更新新图片路径
                List<String> imagePaths = document.getList("image_paths", String.class);
                if (isUpdateImagePath && imagePaths != null && !imagePaths.isEmpty()) {
                    List<String> newImagePath = new ArrayList<>();
                    for (String imagePath : imagePaths) {
                        String oldPath = "/data/instagram/";
                        String newPath = "/data/instagram/new/";
                        if (imagePath != null && imagePath.contains(oldPath) && !imagePath.contains(newPath)) {
                            imagePath = imagePath.replace(oldPath, newPath);
                        }
                        newImagePath.add(imagePath);
                    }
                    document.put("image_paths", newImagePath);
                }
                // 更新原有数据
                JsonRespDto<Document> oneById = insPostController.findOneById(id);
                if (JsonRespUtil.isSuccess(oneById)) {
                    Document data = oneById.getData();
                    if (data != null) {
                        List<Document> timingSequenceData = data.getList("timingSequenceData", Document.class);
                        if (timingSequenceData != null && !timingSequenceData.isEmpty()) {
                            // 更新数据
                            List<Document> updateData = document.getList("timingSequenceData", Document.class);
                            List<Document> newData = new ArrayList<>(timingSequenceData);
                            if (updateData != null && !updateData.isEmpty()) {
                                newData.addAll(updateData);
                                log.info("更新数据字段 'timingSequenceData'; newVal={}, oldVal={}", newData, timingSequenceData);
                            }
                            document.put("timingSequenceData", newData);
                        }
                        List<String> oldData = data.getList("image_paths", String.class);
                        if (oldData != null && !oldData.isEmpty()) {
                            // 更新数据
                            List<String> updateData = document.getList("image_paths", String.class);
                            List<String> newData = new ArrayList<>(oldData);
                            if (updateData != null && !updateData.isEmpty()) {
                                boolean updated = false;
                                for (String updateDatum : updateData) {
                                    if (!newData.contains(updateDatum)) {
                                        updated = true;
                                        newData.add(updateDatum);
                                    }
                                }
                                if (updated) {
                                    log.info("更新数据字段 'image_paths'; newVal={}, oldVal={}", newData, oldData);
                                }
                            }
                            document.put("image_paths", newData);
                        }
                    }
                }
                JsonRespDto<UpdateResult> addOrUpdateOne = insPostController.addOrUpdateOne(document);
                if (JsonRespUtil.isSuccess(addOrUpdateOne)) {
                    deleteRemotePost(document);
                    long past = System.currentTimeMillis() - start;
                    log.info("同步数据成功! id={}, 耗时= {}, 已同步 {} 条", id, DateFormatUtil.formatMs(past), atomicLong.incrementAndGet());
                } else {
                    log.error("同步帖子数据失败! id={} result={}", id, addOrUpdateOne);
                }
            } catch (Exception e) {
                if (e instanceof MongoException) {
                    String message = e.getMessage();
                    log.error("同步帖子数据失败! 数据库连接异常! {}", message);
                    break;
                } else {
                    log.error("同步帖子数据失败! id={}, document={}", id, document, e);
                }
            }
        }
    }

    private void deleteRemotePost(Document file) {
        if (null == file) {
            log.error("删除远端数据失败! 错误的参数! file= null");
            return;
        }
        // [delete] http://e.7mo.org:8068/Ins/post/123
        String id = file.getString("id");
        String postDelete = String.format(InsUrl.POST_DELETE_FORMAT, id);
        String delUrl = middleUrl + postDelete;

        JsonRespDto<Document> delete = restTemplateUtils.delete(delUrl, new TypeReference<JsonRespDto<Document>>() {
        });
        if (JsonRespUtil.isSuccess(delete)) {
            Document data = delete.getData();
            int deletedCount = data.getInteger("deletedCount", 0);
            log.info("删除远端数据成功! id= {}, deletedCount= {}", id, deletedCount);
        } else {
            log.info("删除远端数据失败! id= {}, resp= {}", id, delete);
        }
    }

    private List<Document> extractPostList(List<String> data) {
        List<Document> fileList = new ArrayList<>();
        if (null == data) {
            return null;
        }
        for (String datum : data) {
            try {
                Document document = Document.parse(datum);
                if (document != null) {
                    fileList.add(document);
                } else {
                    log.error("解析帖子数据失败! null! datum= {}", datum);
                }
            } catch (Exception e) {
                log.error("解析帖子数据失败! datum= {}", datum, e);
            }
        }
        return fileList;
    }

    public static void main(String[] args) {
        System.out.println("PostSchedule");
        try {
            RestTemplateUtils restTemplateUtils = new RestTemplateUtils();
            String postUrl = "http://e.7mo.org:8068/Ins/post?pageSize=100&pageNumber=1";
            JsonRespDto<List<org.bson.Document>> listJsonRespDto = restTemplateUtils.get(postUrl, new TypeReference<JsonRespDto<List<org.bson.Document>>>() {
            });
            int code = listJsonRespDto.getCode();
            System.out.println("code = " + code);


            String id = "2747395785971559483";
            String postDelete = String.format(InsUrl.POST_DELETE_FORMAT, id);
            String delUrl = "http://e.7mo.org:8068" + postDelete;

            JsonRespDto<Document> delete = restTemplateUtils.delete(delUrl, new TypeReference<JsonRespDto<Document>>() {
            });

            System.out.println("delete" + delete);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
